#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#ifndef _GATHER_CHANNEL_H_
#define _GATHER_CHANNEL_H_
/***********************************************************************
  *Copyright 2020-03-06, pyfree
  *
  *File Name       : gchannel.h
  *File Mark       : 
  *Summary         : 采集信道父类
  *
  *Current Version : 1.00
  *Author          : pyfree
  *FinishDate      :
  *
  *Replace Version :
  *Author          :
  *FinishDate      :

 ************************************************************************/
#include "conf_channel.h"
#include "queuedata.h"
#include "queuedata_single.h"
#include "datadef.h"
#include "hashmap.h"

#include <set>

class BusinessDef;	//业务数据单体类,可以看做业务数据的全局变量使用
class luadisp;		//lua脚本接口

class GatherChannel
{
public:
	GatherChannel(int gid);
	virtual ~GatherChannel(void);

	/**
	 * 上行接口调用本采集信道的下控执行函数,需要在子类重写该函数
	 * @param exetype {int} 执行类型{1,查询;2,设值}
	 * @param type {PType} 信息点类型{遥信/遥测等}
	 * @param pid {int} 信息点编号
	 * @param val {float} 值
	 * @param task_id {ulong} 任务编号
	 * @return {bool } 
	 */
	virtual void downControl(int exetype, int type, int pid, float val, unsigned long task_id=0)
	{

	};
private:
	/**
	 * 本实例初始化
	 * @return {void } 
	 */
	void init(int gid);
	/**
	 * 初始化脚本接口实例
	 * @return {void } 
	 */
	void initLua();
	/**
	 * 重新加载解析脚本
	 * @return {void } 
	 */
	void reSetlua();
	/**
	 * 析构脚本接口实例
	 * @return {void } 
	 */
	void releaseLua();
	/**
	 * 设置采集信道下计算点的数值,计算点数值是根据实际采集点进行公式计算得到
	 * 而实际采集点的数值集合通常是总召查询返回报文解析获得
	 * @param _mapVals {map} 实时报文解析获得的实际点当前数值
	 * @return {void } 
	 */
	void setPFuncValue(std::map<int, float> _mapVals);//计算点设值
//////////////////////////////////////////////////////////////////
protected:
	/**
	 * 状态重置,一般在信道重新打开调用
	 * @return {void } 
	 */
	void pointInitReset();
	/**
	 * 定时上送采集信道下的各个信息点态势,包括信道的通信状态,前提需要和信息点一样配置
	 * @return {void } 
	 */
	void TimeUpState();
	/**
	 * 通过lua脚本对返回报文解析,获得'点,值;点,值......'的字符集合
	 * @param up_cmd {string} 上行(返回)报文
	 * @param down_cmd {string} 下行报文
	 * @param task_id {ulong} 任务编号
	 * @param control_flag {bool} 下控(设值)或查询
	 * @param dev_addr {ulong} 设备编号,作为服务端级联下级采集服务时,采用ip的整型格式标识设备编号
	 * @return {void } 
	 */
	void msgAnalysis(const std::string up_cmd,std::string down_cmd,unsigned long task_id
		,bool control_flag=false, unsigned long dev_addr=1);
	/**
	 * 设置采集信道的某设备某地址采集数值,并快速查找到采集信道下的配置信息点
	 * @param addr {int} 地址编号
	 * @param val {float} 值
	 * @param task_id {ulong} 任务编号
	 * @param dev_addr {ulong} 设备编号,作为服务端级联下级采集服务时,采用ip的整型格式标识设备编号
	 * @return {void } 
	 */
	void setValue(int addr, float val, unsigned long task_id = 0, unsigned long dev_addr=1);
	/**
	 * 设置采集信道下的配置信息点的值
	 * @param pid {int} 信息点编号
	 * @param type {PType} 信息点类型
	 * @param val {float} 值
	 * @param changeUp {bool} 数据是否变更
	 * @param task_id {ulong} 任务编号
	 * @return {void } 
	 */
	void setPValue(int pid, pyfree::PType type, float val
		,bool changeUp=false, unsigned long task_id = 0);
	/**
	 * 通过lua脚本调用,将下控信息转换为协议报文
	 * @param exetype {int} 执行类型{1,查询;2,设值}
	 * @param type {PType} 信息点类型{遥信/遥测等}
	 * @param pid {int} 信息点编号
	 * @param val {float} 值
	 * @param cmd {string&} 转换后的协议报文
	 * @param checktype {int&} 信息点类型
	 * @param dev_addr {int&} 设备编号
	 * @param task_id {ulong} 任务编号
	 * @return {bool } 
	 */
	bool getCmd(int exetype, int type, int pid, float val
		, std::string &cmd,int &checktype,  unsigned long &dev_addr,unsigned long task_id=0);
protected:
	//通道相关信息或业务标识
	ChannelAssistInfo cstate;
	//读取采集端数据缓存
	QueueData<ChannelCmd> *ReadDatas;
	//写入采集端数据缓存
	QueueData<ChannelCmd> *WriteDatas;
	//轮询命令,来自脚本读入解析获得
	TotalCall cmdlist;
	//业务数据
	BusinessDef *ptr_BDef;
	//采集信道属性配置
	pyfree::GatherAtts gatheratts;
	//采集信道协议配置
	pyfree::ProtocolDef protodefs;
	//
	static float FLIMIT;
private:
	std::set<unsigned long> dev_addrs;
	//采集信道下的地址编号与信息编号映射,方便快速定位
	std::map<KeyObj_GAddr, pyfree::PInfo> addr_pid_pinfos;
	//采集信道下的信息编号与地址编号映射,方便快速定位
	std::map<int, pyfree::PInfo> pid_addr_pinfos;
	//采集信道下的信息计算点编号到信息地址映射
	std::map<int, pyfree::PFuncInfo> pid_addr_pfinfos;

	//通信数据解析脚本类
	luadisp *luaScript;
	//脚本解析错误次数
	unsigned int error_lua_count;
	static const unsigned int error_lua_max = 3;
	//写入转发端口的数据缓存,有采集信道管理线程进行业务中转
	QueueDataSingle<ChannelToTransmit> *ToTranDatas;
	
};

#endif
